import { permission } from "process";

namespace study41 {

  /**
   * keyof 
   * 1. 获取某个对象类型的所有键的集合 - keyof 获取type、interface、class的键的集合
   * 2. 应用场景 - 会用keyof约束参数类型,确保只能访问指定对象存在的属性
   *             - 用 keyof 结合 in 关键字，遍历对象属性
   */

  // 1. 基本概念
  // 1.1 获取type的所有键的集合
  type Person = {
    name: string;
    age: number;
    gender: string;
  }

  type PersonKeys = keyof Person // "name" | "age" | "gender"

  // 1.2 获取interface的所有键的集合
  interface Person1 {
    name: string;
    age: number;
    gender: string;
  }

  type PersonKeys1 = keyof Person // "name" | "age" | "gender"

  // 1.3 获取class的所有键的集合
  class Person2 {
    constructor(
      public name: string,
      public age: number,
      public gender: string
    ) { }
  }

  type PersonKeys2 = keyof Person2 // "name" | "age" | "gender"

  // 1.4 获取对象所有键的集合
  // keyof不直接获取对象的键的集合，而是获取对象类型的所有键的集合。
  const Person0 = {
    name: 'aaa',
    age: 12,
    gender: 'da'
  }
  type Personn = typeof Person0
  type PersonKeys0 = keyof Personn // "name" | "age" | "gender"

  // 2. 应用场景
  // 2.1 约束函数参数类型,确保参数是对象的某个键值
  function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key]
  }

  let person = {
    name: "suchenfeng",
    age: 3
  }

  let name = getProperty(person, "name")
  // let invalid = getProperty(person, "invalid") // error: Argument of type '"invalid"' is not assignable to parameter of type 'keyof T'.

  // 2.2 动态属性访问 - 结合泛型和索引类型,可以让 TypeScript 在编译时推断出对象属性的类型，提升类型安全性。
  type Config = {
    apiEndpoint: string;
    timeout: number;
  }

  function updateConfig<k extends keyof Config>(key: k, value: Config[k]) { }

  updateConfig("apiEndpoint", "http://localhost:3000")
  updateConfig("timeout", 1000)
  // updateConfig("invalid", 1000) // error: Argument of type '"invalid"' is not assignable to parameter of type 'keyof Config'.

  // 2.3 遍历对象的属性 - 可以使用 keyof 结合 in 关键字，来遍历对象类型的所有键。
  type Person3 = {
    name: string;
    age: number;
    isEmployed: boolean;
  }

  type PersonPartial = {
    [k in keyof Person3]?: Person3[k]
  }

  // 等同于
  // type PersonPartial = {
  //   name?: string | undefined;
  //   age?: number | undefined;
  //   isEmployed?: boolean | undefined;
  // }

  let partialPerson: PersonPartial = {}
  partialPerson.name = "suchenfeng"
  partialPerson.age = 3
  partialPerson.isEmployed = true

  // 2.4 结合 typeof 使用,获取某个对象的键的联合类型
  const settings = {
    theme: "dark",
    version: "1.0",
    useCache: true,
  }

  type SettingsKeys = keyof typeof settings

  function updateSetting(key: SettingsKeys, value: typeof settings[SettingsKeys]) { }

  // 3. 实战案例
  // 3.1 增强对象类型的灵活性 - 设置一些状态值
  type APIResponse = {
    data: object;
    error: string;
  }

  type APIResponseKeys = keyof APIResponse

  function handleResponse(key: APIResponseKeys, response: APIResponse) {
    if (key === "error") {
      console.log(response[key]);
    } else {
      console.log(response[key]);
    }
  }

  // 3.2 实现类型安全的字典 -结合联合类型
  type UserRole = 'admin' | 'user' | 'guest'

  type Permissions = {
    [role in UserRole]: string[]
  }

  // 等同于
  // type Permissions = {
  //   admin: string[];
  //   user: string[];
  //   guest: string[];
  // }

  const permissions: Permissions = {
    admin: ['create', 'update', 'delete'],
    user: ['read'],
    guest: []
  }
  // keyof Permissions 限制了 getPermissions 函数只能接受合法的 UserRole 作为参数
  function getPermissions(role: keyof Permissions): string[]{
    return permissions[role]
  }
}